package com.gateway.admin.config;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.gateway.admin.gay.GayPublish;
import com.gateway.common.constants.Constants;
import com.gateway.common.enums.ResultEnum;
import com.gateway.common.utils.IpUtils;
import com.gateway.common.utils.StringUtils;
import com.gateway.system.domain.dto.FilterUrlDto;
import com.gateway.system.domain.dto.WhiteIpDto;
import com.gateway.system.domain.entity.BasicRoute;
import com.gateway.system.service.BasicRouteService;
import com.gateway.system.service.FilterUrlService;
import com.gateway.system.service.WhiteIpService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;

import com.gateway.config.gay.nacos.*;


/**
 * @author admin
 */
@Component
@Slf4j
public class AuthorizeFilter implements GlobalFilter, Ordered {

    @Autowired
    FilterUrlService filterUrlService;

    @Autowired
    BasicRouteService basicRouteService;

    @Autowired
    WhiteIpService whiteIpService;

    @Autowired
    NacosServiceConfig nacosServiceConfig;

    @Autowired
    GayPublish gayPublish;

    @SneakyThrows
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put(Constants.CODE, ResultEnum.UNAUTHORIZED.getCode());
        jsonObject.put(Constants.MESSAGE, ResultEnum.UNAUTHORIZED.getMessage());
        ServerHttpRequest request = exchange.getRequest();
        //设置请求
        ServerHttpRequest.Builder mutate = request.mutate();
        //重置请求头
        mutate.headers(httpHeaders -> {
            //httpHeaders 封装了所有的请求头
            String traceId = StringUtils.getUUID();
            httpHeaders.set(Constants.TRACE_ID, traceId);
        });
        ServerHttpRequest serverHttpRequest = mutate.build();
        ServerHttpResponse serverHttpResponse = exchange.getResponse();
        if(!getPermissionIp(serverHttpRequest)){
            //白名单限制
            jsonObject.put(Constants.CODE, ResultEnum.REQUEST_IP_LIMIT.getCode());
            jsonObject.put(Constants.MESSAGE, ResultEnum.REQUEST_IP_LIMIT.getMessage());
            byte[] bytes = jsonObject.toJSONString().getBytes(StandardCharsets.UTF_8);
            DataBuffer buffer = serverHttpResponse.bufferFactory().wrap(bytes);
            return serverHttpResponse.writeWith(Flux.just(buffer));
        }
        //获取路径
        String requestPath = serverHttpRequest.getPath().toString();
        log.info("地址{}", requestPath);
        FilterUrlDto filterUrlDto = permission(requestPath);
        log.info("过滤的url{}", JSONObject.toJSONString(filterUrlDto));
        if(filterUrlDto != null){
            Integer isAuth = filterUrlDto.getIsAuth();
            //如果需要授权，并且需要权限校验
            if(Constants.NUM_ONE.equals(isAuth)){
                //如果授权通过
                if(isAuth()){
                    //灰度发布
                    gayPublish.gayPublish(filterUrlDto.getServiceName(), serverHttpRequest);
                    return chain.filter(exchange);
                }
                //不通过
                byte[] bytes = jsonObject.toJSONString().getBytes(StandardCharsets.UTF_8);
                DataBuffer buffer = serverHttpResponse.bufferFactory().wrap(bytes);
                return serverHttpResponse.writeWith(Flux.just(buffer));
            }
            return chain.filter(exchange);
        }
        jsonObject.put(Constants.CODE, ResultEnum.URL_NOT_EXIST.getCode());
        jsonObject.put(Constants.MESSAGE, ResultEnum.URL_NOT_EXIST.getMessage());
        byte[] bytes = jsonObject.toJSONString().getBytes(StandardCharsets.UTF_8);
        DataBuffer buffer = serverHttpResponse.bufferFactory().wrap(bytes);
        return serverHttpResponse.writeWith(Flux.just(buffer));
    }

    @Override
    public int getOrder() {
        return 0;
    }

    /**
     * 判断是否在网关中对接口进行注册
     * @param requestPath
     * @return
     */
    public FilterUrlDto permission(String requestPath){
        FilterUrlDto filterUrlDto =  filterUrlService.selectFilterUrlByUrl(requestPath);
        if(filterUrlDto != null){
            if(filterUrlDto.getFilterUrl().equals(requestPath)){
                return filterUrlDto;
            }
        }
        return null;
    }

    public boolean getPermissionIp(ServerHttpRequest serverHttpRequest){
        InetSocketAddress inetSocketAddress = serverHttpRequest.getRemoteAddress();
        InetAddress inetAddress = inetSocketAddress.getAddress();
        String ip = inetAddress.getHostAddress();
        WhiteIpDto whiteIpDto = whiteIpService.selectWhiteIp(ip);
        if(whiteIpDto != null){
            return false;
        }
        return true;
    }

    /**
     * 是否需要权限校验
     * @return
     */
    public boolean isAuth(){
        return true;
    }
}